/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ads.hash;

/**
 *
 * @author framet-lap
 */
public class HashTable {

    private Participant[] table;

    public HashTable(int size) {
        table = new Participant[size];
    }

    public void add(Participant o) throws HashTableOverflowException {
        int index = o.hashCode() % table.length;
        sqrtExploreAdd(index, 0, o);
    }

    private void sqrtExploreAdd(int index, int indexDifference, Participant o) throws HashTableOverflowException {
        int currentIndexPositive = index + indexDifference;
        int currentIndexNegative = index - indexDifference;
        if (currentIndexPositive < table.length && table[currentIndexPositive] == null) {
            table[currentIndexPositive] = o;
        } else if (currentIndexPositive >= 0 && table[currentIndexNegative] == null) {
            table[currentIndexNegative] = o;
        } else {
            indexDifference = switchFirstIndexDifference(indexDifference);
            if (currentIndexPositive < table.length || currentIndexPositive >= 0) {
                sqrtExploreAdd(index, indexDifference * 2, o);
            } else {
                throw new HashTableOverflowException();
            }
        }
    }

    private int sqrtExploreGetRecursive(int index, int indexDifference, int id, boolean emptyLowerIndex, boolean emptyUpperIndex) {
        int currentIndexPositive = index + indexDifference;
        int currentIndexNegative = index - indexDifference;
        if (!emptyUpperIndex && currentIndexPositive < table.length) {
            emptyUpperIndex = table[currentIndexPositive] == null;
            if (table[currentIndexPositive].getId() == id) {
                return currentIndexPositive;
            }
        }
        if (!emptyLowerIndex && currentIndexNegative >= 0) {
            emptyLowerIndex = table[currentIndexNegative] == null;
            if (table[currentIndexNegative].getId() == id) {
                return currentIndexNegative;
            }
        }
        indexDifference = switchFirstIndexDifference(indexDifference);
        if ((emptyLowerIndex && emptyUpperIndex) || (currentIndexPositive < table.length || currentIndexPositive >= 0)) {
            return sqrtExploreGetRecursive(index, indexDifference * 2, id, emptyLowerIndex, emptyUpperIndex);
        }
        return -1;
    }

    private int switchFirstIndexDifference(int indexDifference) {
        if (indexDifference == 0 || indexDifference == 1) {
            return 2;
        }
        return indexDifference;
    }

    private boolean sqrtExploreContains(Participant o) {
        int index = o.hashCode() % table.length;
        return sqrtExploreGetRecursive(index, 0, o.getId(), false, false) != -1;
    }

    private Participant sqrtExploreGet(int hashCode, int id) throws ParticipantNotFound {
        int realIndex = sqrtExploreGetRecursive(hashCode, 0, id, false, false);
        if (realIndex != -1) {
            return table[realIndex];
        }
        throw new ParticipantNotFound(String.valueOf(id));
    }
    
    public Participant getParticipant(Participant p) throws ParticipantNotFound{
        return getObject(p.hashCode(), p.getId());
    }

    public Participant getObject(int hashCode, int id) throws ParticipantNotFound {
        return sqrtExploreGet(hashCode, id);
    }

    public boolean contains(Participant o) {
        return sqrtExploreContains(o);
    }
}
